home *** CD-ROM | disk | FTP | other *** search
- /*
- * File: HotKeys.c
- *
- * Abstract: Implements both the low level and GUI of hot keys.
- *
- * Licensing: This code may be used without fees provided that proper
- * copyright notice given.
- *
- * History: 1.0.0 RSM 93-11-29 Created first version
- *
- * ©1993 One Step Beyond
- */
-
- #ifdef THINK_C
- # include <MacHeaders>
- #else
- # include <Dialogs.h>
- # include <Memory.h>
- # include <Resources.h>
- # include <ToolUtils.h>
- #endif
- #include <Script.h>
- #include "HotKeys.h"
-
-
- /*
- * Constants
- */
- #define kSicnBytes 32 // # of bytes per SICN
- #define kSicnSize 16 // pixel height and width
- #define modFlagsMask (cmdKey+shiftKey+optionKey+controlKey)
-
-
- /*
- * Some quicky types
- */
- typedef unsigned char uchar;
-
-
- /*
- * Static data
- */
- static uchar sicnKeys[] = { 0x37, 0x38, 0x3A, 0x3B, // cmd, shift, opt, cntrl
- 0x7D, 0x7E, 0x7B, 0x7C, // arrows (left, right, down, up)
- 0x33, 0x75, // del, fwd del
- 0xFF };
-
- static uchar strKeys[] = { 0x35, 0x24, 0x4C, 0x30, 0x31, 0x47, // esc, ret, ent, tab, space, clear
- 0x72, 0x73, 0x74, 0x77, 0x79, // help, home, pg up, end, pg down,
- 0x7A, 0x78, 0x63, 0x76, 0x60, // F1-F5
- 0x61, 0x62, 0x64, 0x65, 0x6D, // F6-F10
- 0x67, 0x6F, 0x69, 0x6B, 0x71, // F9-F15
- 0xFF };
-
- static uchar numKPadKeys[] = { 0x41, 0x43, 0x45, 0x4B, 0x4E, 0x51, 0x52, 0x53,
- 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5B, 0x5C,
- 0xFF };
-
- /*
- * Local function prototypes
- */
-
- static short DrawModifiers( const Rect*, const Handle, const short );
- static void DrawSicnKey( const HotKey*, const Rect*, const Handle, const short );
- static void DrawStrKey( const HotKey*, const Rect* );
- static void PlotSICN( const Rect*, const short, const Handle );
- static short KeyCodeToAscii( const short );
- static short ToUpper( const short );
- static short InBytes( const short, const uchar* );
-
-
- /*
- * Global variables
- */
- short gHotKeySICNRsrcID = 1024;
- short gHotKeyDLOGRsrcID = 1024;
- short gHotKeyStrsRsrcID = 1024;
-
-
- /*
- * return 1 if the msg & mods match the given hotkey, 0 otherwise
- */
- short
- IsHotKey( const HotKey *key,
- const long msg,
- const short mods )
- {
- uchar keyCode = (msg & keyCodeMask) >> 8;
- uchar modFlags = (mods & modFlagsMask) >> 8;
-
- return key->onOff && ( key->mods == modFlags ) && ( key->keyCode == keyCode );
- }
-
-
- /*
- * Set the given hotkey given the msg and mods
- */
- void
- SetHotKey( HotKey *key,
- const long msg,
- const short mods )
- {
- key->onOff = 1;
- key->filler = 0;
- key->mods = (mods & modFlagsMask) >> 8;
- key->keyCode = (msg & keyCodeMask) >> 8;
- }
-
-
- /*
- * Unsets a hot key to nothing.
- */
- void
- ClearHotKey( HotKey *key )
- {
- key->onOff = 0;
- }
-
-
- /*
- * Set's the hot key using a "modal" dialog.
- */
- void
- SetHotKeyDlog( HotKey *key )
- {
- GrafPtr savePort;
- DialogPtr dp;
- EventRecord evt;
- unsigned long wait;
- Handle ihdl;
- Rect irect;
- short itype;
-
- GetPort( &savePort );
- dp = GetNewDialog( gHotKeyDLOGRsrcID, NULL, (GrafPtr)-1L );
- if( dp ){
- SetPort( dp );
- DrawDialog( dp );
- GetDItem( dp, 2, &itype, &ihdl, &irect );
- FrameRect( &irect );
-
- do{
- WaitNextEvent( everyEvent, &evt, 300, NULL );
- }while( !(evt.what == mouseDown || evt.what == keyDown) );
-
- if( evt.what == keyDown ){
- SetHotKey( key, evt.message, evt.modifiers );
- InsetRect( &irect, 1, 1 );
- DrawHotKey( key, &irect );
-
- wait = TickCount() + 30;
- while( wait > TickCount() )
- WaitNextEvent( 0, &evt, 6, NULL );
- }
-
- DisposeDialog( dp );
- }
- SetPort( savePort );
- }
-
-
- /*
- * Draw the hot key's representation in the current port.
- * Note: this uses's the port's current font, size, face and colors
- */
- OSErr
- DrawHotKey( const HotKey *key,
- const Rect *bnds )
- {
- RgnHandle saveClip;
- Handle sicnH;
- Rect r;
- short idx;
- OSErr err;
- uchar ascii;
-
- if( key->onOff == 0 )
- return noErr;
-
- if( (saveClip = NewRgn()) == NULL )
- return MemError();
-
- if( (sicnH = GetResource( 'SICN', gHotKeySICNRsrcID )) == NULL )
- return ResError();
-
- GetClip( saveClip );
- ClipRect( bnds );
-
- r = *bnds;
- r.left = DrawModifiers( &r, sicnH, key->mods );
-
- if( idx = InBytes( key->keyCode, sicnKeys ) )
- DrawSicnKey( key, &r, sicnH, idx );
- else
- DrawStrKey( key, &r );
-
- SetClip( saveClip );
- DisposeRgn( saveClip );
- return noErr;
- }
-
-
- /*
- * Draw the modifier keys by bit shifting throught the modifier field flags.
- * If the bit is set, draw the cooresponding SICN. Does not change the pen
- * location.
- * Returns the right horizontal position after the last icon drawn.
- */
- static short
- DrawModifiers( const Rect *bnds,
- const Handle sicnH,
- const short mods )
- {
- Rect r;
- short idx, mask;
-
- r.left = bnds->left + 1;
- r.top = bnds->top + ((bnds->bottom - bnds->top) - kSicnSize) / 2;
- r.right = r.left + kSicnSize;
- r.bottom = r.top + kSicnSize;
-
- idx = 1;
- mask = 0x01;
- do{
- if( mask & mods ){
- PlotSICN( &r, idx, sicnH );
- OffsetRect( &r, 12, 0 );
- }
- idx++;
- mask <<= 1;
- if( mask == 0x04 ) // Skip the caps lock
- mask <<= 1;
- }while( !(mask & 0x80) );
-
- return r.left;
- }
-
-
- /*
- *
- */
- static void
- DrawSicnKey( const HotKey *key,
- const Rect *bnds,
- const Handle sicnH,
- const short idx )
- {
- Rect r;
-
- r.left = bnds->left + 2;
- r.top = bnds->top + ((bnds->bottom - bnds->top)-kSicnSize) / 2;
- r.right = r.left + kSicnSize;
- r.bottom = r.top + kSicnSize;
- LoadResource( sicnH );
- PlotSICN( &r, idx, sicnH );
- }
-
-
- /*
- *
- */
- static void
- DrawStrKey( const HotKey *key,
- const Rect *bnds )
- {
- Str32 s;
- GrafPtr port;
- short fontSize, height, idx;
- uchar ascii;
-
- if( InBytes( key->keyCode, numKPadKeys ) ){
- s[0] = 3;
- s[1] = '[';
- s[2] = ascii;
- s[3] = ']';
- }else if( idx = InBytes( key->keyCode, strKeys ) ){
- GetIndString( s, gHotKeyStrsRsrcID, idx );
- }else{
- ascii = KeyCodeToAscii( key->keyCode );
- if( ascii != -1 ){
- s[0] = 1;
- s[1] = (ascii>='a' && ascii<='z') ? (ascii-'a'+'A') : ascii;
- }else{
- s[0] = 4;
- s[1] = '(';
- s[2] = s[3] = '?';
- s[4] = ')';
- }
- }
-
- GetPort( &port );
- height = bnds->bottom - bnds->top;
- fontSize = port->txSize ? port->txSize : 12;
-
- MoveTo( bnds->left + 2, bnds->bottom - ((height-fontSize)/2) - 2 );
- DrawString( s );
- }
-
-
- /*
- * Convert a virtual keycode to it's cooresponding ASCII code using the 'KCHR'
- * resource. This code is adapted from the "kcapApp" snippet by Greg Robbins
- * of Apple DTS.
- */
- static short
- KeyCodeToAscii( const short keyCode )
- {
- Handle kchrH;
- long state;
- short kchrID;
- uchar ascii;
-
- kchrID = GetScript( GetEnvirons(smKeyScript), smScriptKeys );
- kchrH = RGetResource( 'KCHR', kchrID );
- if( kchrH == NULL )
- return -1;
-
- state = 0;
- ascii = KeyTrans( *kchrH, keyCode, &state );
-
- if( HomeResFile( kchrH ) > 1 )
- ReleaseResource( kchrH );
-
- return ascii;
- }
-
-
- /*
- * Return the position (one based) in the given array of unsigned chars of the
- * given code.
- * Note: similar to the function strchr() in string.h.
- */
- static short
- InBytes( const short code, const uchar *kp )
- {
- short idx = 1;
-
- do{
- if( *kp == code ){
- return idx;
- }else{
- kp++;
- idx++;
- }
- }while( *kp != 0xFF );
- return 0;
- }
-
-
- /*
- * Utility routing to plot a SICN. The idx is one (1) based.
- */
- static void
- PlotSICN( const Rect *bnds,
- const short idx,
- const Handle sicnH )
- {
- BitMap bm;
- char hstate;
-
- hstate = HGetState( sicnH );
- HLock( sicnH );
- bm.baseAddr = *sicnH + (idx-1) * kSicnBytes;
- bm.rowBytes = kSicnBytes / kSicnSize;
- bm.bounds.top = bm.bounds.left = 0;
- bm.bounds.bottom = bm.bounds.right = kSicnSize;
-
- StdBits( &bm, &bm.bounds, bnds, srcCopy, NULL );
- HSetState( sicnH, hstate );
- }
-
-